package com.ben.utils.log

import android.annotation.SuppressLint
import java.util.*

object Logger {

    private const val TAG = "LogTag"

    private var logEnable = false
    private var debugMode = false
    private var iLog: ILog? = null

    fun setLogEnable(enable: Boolean): Logger {
        this.logEnable = enable
        return this
    }

    /**
     *  设置日志打印debug模式，debug模式下会打印堆栈信息
     */
    fun setDebugMode(debugMode: Boolean = true): Logger {
        this.debugMode = debugMode
        return this
    }

    fun setLog(iLog: ILog): Logger {
        this.iLog = iLog
        return this
    }

    @SuppressLint("AvoidUsageApiCheck")
    private fun printLog(tag: String, veryLongString: String, type: Int) {
        val maxLogSize = 2000
        checkLogImpl()
        for (i in 0..veryLongString.length / maxLogSize) {
            val start = i * maxLogSize
            var end = (i + 1) * maxLogSize
            end = if (end > veryLongString.length) veryLongString.length else end
            when (type) {
                1 -> iLog?.v(tag, veryLongString.substring(start, end))
                2 -> iLog?.d(tag, veryLongString.substring(start, end))
                3 -> iLog?.i(tag, veryLongString.substring(start, end))
                4 -> iLog?.w(tag, veryLongString.substring(start, end))
                5 -> iLog?.e(tag, veryLongString.substring(start, end))
                6 -> iLog?.wtf(tag, veryLongString.substring(start, end))
            }
        }
    }

    private fun checkLogImpl() {
        if (iLog == null) iLog = ILogImpl()
    }

    private fun buildLog(type: Int, tagStr: String?, objectMsg: Any?) {
        if (!logEnable) return
        if (debugMode) {
            val stackTrace = Thread.currentThread().stackTrace
            val index = 4
            val className = stackTrace[index].fileName
            var methodName = stackTrace[index].methodName
            val lineNumber = stackTrace[index].lineNumber
            val tag = tagStr ?: className
            methodName = methodName.substring(0, 1)
                .uppercase(Locale.getDefault()) + methodName.substring(1)
            val stringBuilder = StringBuilder()
            stringBuilder.append("[ (").append(className).append(":").append(lineNumber)
                .append(")#").append(methodName).append(" ] ")
            val msg: String = objectMsg?.toString() ?: "Log with null Object"
            stringBuilder.append(msg)
            val logStr = stringBuilder.toString()
            printLog(tag, logStr, type)
        } else {
            printLog(tagStr ?: "", objectMsg?.toString() ?: "", type)
        }
    }

    fun v(tag: String? = TAG, msg: String?) {
        buildLog(1, tag, msg)
    }

    fun v(msg: String?) {
        buildLog(1, TAG, msg)
    }

    fun d(tag: String? = TAG, msg: String) {
        buildLog(2, tag, msg)
    }

    fun d(msg: String) {
        buildLog(2, TAG, msg)
    }

    @JvmStatic
    fun i(tag: String? = TAG, msg: String?) {
        buildLog(3, tag, msg)
    }

    fun i(msg: String?) {
        buildLog(3, TAG, msg)
    }

    fun w(tag: String? = TAG, msg: String?) {
        buildLog(4, tag, msg)
    }

    fun w(msg: String?) {
        buildLog(4, TAG, msg)
    }

    @JvmStatic
    fun e(tag: String? = TAG, msg: String?) {
        buildLog(5, tag, msg)
    }

    fun e(msg: String?) {
        buildLog(5, TAG, msg)
    }

    fun wtf(tag: String? = TAG, msg: String?) {
        buildLog(6, tag, msg)
    }

    fun wtf(msg: String?) {
        buildLog(6, TAG, msg)
    }

    private class ILogImpl : ILog {
        override fun v(tag: String?, msg: String) {
            android.util.Log.v(tag, msg)
        }

        override fun d(tag: String?, msg: String) {
            android.util.Log.d(tag, msg)
        }

        override fun i(tag: String?, msg: String) {
            android.util.Log.i(tag, msg)
        }

        override fun w(tag: String?, msg: String) {
            android.util.Log.w(tag, msg)
        }

        override fun e(tag: String?, msg: String) {
            android.util.Log.e(tag, msg)
        }

        override fun wtf(tag: String?, msg: String) {
            android.util.Log.wtf(tag, msg)
        }
    }

    interface ILog {
        fun v(tag: String?, msg: String)
        fun d(tag: String?, msg: String)
        fun i(tag: String?, msg: String)
        fun w(tag: String?, msg: String)
        fun e(tag: String?, msg: String)
        fun wtf(tag: String?, msg: String)
    }
}
